<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > S3C2410下WinCE6.0的啟動(dòng)過(guò)程詳解

          S3C2410下WinCE6.0的啟動(dòng)過(guò)程詳解

          作者: 時(shí)間:2016-11-20 來(lái)源:網(wǎng)絡(luò) 收藏
          通過(guò)前兩篇文章的介紹,我們已經(jīng)知道NBOOT用來(lái)引導(dǎo)EBOOT,繼而EBOOT加載并引導(dǎo)WinCE操作系統(tǒng)(NK)。那么,WinCE6.0啟動(dòng)過(guò)程又是怎樣的呢?本文基于S3C2410的平臺(tái)做一個(gè)詳細(xì)的分析。需要說(shuō)明的是,WinCE6.0的整個(gè)啟動(dòng)過(guò)程對(duì)于同一類(lèi)型的MCU來(lái)說(shuō)大同小異,如S3C2410和PXA270同屬ARM平臺(tái)的MCU,所以他們的啟動(dòng)過(guò)程是類(lèi)似的,可以說(shuō)唯一的不同就在OAL處,而WinCE操作系統(tǒng)的啟動(dòng)正是從OAL開(kāi)始的。

          OAL(OEM Adaptation Layer)即OEM適配層,它的主要作用是在移植WinCE到新的硬件平臺(tái)時(shí)減少操作系統(tǒng)的修改,通俗的說(shuō)就是為WinCE操作系統(tǒng)抹平MCU的差異,使其能很方便的在不同MCU上運(yùn)行。所以,OAL包括了和系統(tǒng)硬件通訊的最底層代碼。內(nèi)核則通過(guò)OAL跟硬件進(jìn)行交互。邏輯上,OAL是介于CE內(nèi)核和設(shè)備硬件之間的一個(gè)代碼層,是一個(gè)抽象的概念。物理上,OAL和其他一些庫(kù)一起鏈接成可執(zhí)行文件,在WinCE6.0中對(duì)應(yīng)的文件是OAL.exe,這是OAL的客觀存在。WinCE6.0中的OAL跟先前的OAL比,是有一些變化的,它從內(nèi)核中分離出來(lái)成為OAL.exe,而內(nèi)核則變成了Kernel.dll。這樣做的好處是可以單獨(dú)升級(jí)OAL。但整體的OAL結(jié)構(gòu)并沒(méi)有改變,OEM函數(shù)保持一致,OAL和Kernel的接口由共享結(jié)構(gòu)NKGLOBAL實(shí)現(xiàn)。這一部分的具體內(nèi)容下一篇再做介紹。下圖所示為WinCE6.0的OAL設(shè)計(jì)。

          本文引用地址:http://www.ex-cimer.com/article/201611/318750.htm

          在移植WinCE到新的硬件平臺(tái)時(shí),創(chuàng)建OAL是最復(fù)雜的任務(wù)之一。一般來(lái)說(shuō),最簡(jiǎn)單的方法是拷貝一個(gè)跟新的硬件平臺(tái)類(lèi)似的且成熟的OAL,然后根據(jù)硬件的不同進(jìn)行修改,使其滿足目標(biāo)硬件的特定要求。這里不展開(kāi)說(shuō)明,回頭再單獨(dú)整理。
          從EBOOT到OAL.exe的跳轉(zhuǎn)是從OEMLaunch()開(kāi)始的,函數(shù)OEMLaunch()中調(diào)用Launch(dwPhysLaunchAddr),它的實(shí)現(xiàn)代碼如下:



          Code
          LEAF_ENTRYLaunch

          ldrr2,=PhysicalStart
          ldrr3,=(VIR_RAM_START-PHY_RAM_START)

          subr2,r2,r3

          movr1,#0x0070;DisableMMU
          mcrp15,0,r1,c1,c0,0
          nop
          movpc,r2;JumptoPStart
          nop

          ;MMU&cachesnowdisabled.

          PhysicalStart

          movr2,#0
          mcrp15,0,r2,c8,c7,0;FlushtheTLB
          movpc,r0;Jumptoprogramwearelaunching.

          函數(shù)Launch()的參數(shù)為物理地址,因?yàn)樵谔D(zhuǎn)之前已將MMU關(guān)閉。該地址可通過(guò)VIEWBIN來(lái)查看,如下圖所示:


          如何確定這個(gè)地址對(duì)應(yīng)的是NK.bin中的哪一個(gè)文件呢,先前說(shuō)是OAL.exe,證據(jù)何在。在PB6.0中增加了瀏覽NK.bin的功能,我們可以利用此功能查看NK.bin的詳細(xì)情況,如下圖所示:



          從上圖中可以看出0x80205394處對(duì)應(yīng)的是NK.exe,而這里的NK.exe即為OAL.exe。
          至此,我們已經(jīng)知道EBOOT是如何跳轉(zhuǎn)到OAL.exe中的了。接下來(lái)繼續(xù)看OAL.exe的執(zhí)行過(guò)程。
          OAL的啟動(dòng)代碼如下:

          Code
          LEAF_ENTRYStartUp

          ;ComputetheOEMAddressTablesphysicaladdressand
          ;loaditintor0.KernelStartexpectsr0tocontain
          ;thephysicaladdressofthistable.TheMMUisnt
          ;turnedonuntilwellintoKernelStart.

          addr0,pc,#g_oalAddressTable-(.+8)
          blKernelStart

          OAL的啟動(dòng)代碼和EBOOT的啟動(dòng)代碼經(jīng)常復(fù)用,但為了代碼的簡(jiǎn)潔,最好還是分開(kāi)實(shí)現(xiàn),而且在EBOOT中如果已經(jīng)初始化了相關(guān)硬件,那么OAL的啟動(dòng)代碼就可以省去那部分工作,可以很簡(jiǎn)練,如上面的代碼所示。

          可以看出,OAL的啟動(dòng)代碼又調(diào)用了函數(shù)KernelStart(),而這個(gè)函數(shù)是在文件C:WINCE600PRIVATEWINCEOSCOREOSNKLDRARMarmstart.s中實(shí)現(xiàn)的,代碼如下:

          Code
          LEAF_ENTRYKernelStart

          movr11,r0;(r11)=&OEMAddressTable(savepointer)

          ;figureoutthevirtualaddressofOEMAddressTable
          movr1,r11;(r1)=&OEMAddressTable(2ndargumenttoVaFromPa)
          blVaFromPa
          movr6,r0;(r6)=VAofOEMAddressTable

          ;convertbaseofPTstoPhysicaladdress
          ldrr4,=PTs;(r4)=virtualaddressofFirstPT
          movr0,r4;(r0)=virtualaddressofFirstPT
          movr1,r11;(r1)=&OEMAddressTable(2ndargumenttoPaFromVa)
          blPaFromVa

          movr10,r0;(r10)=ptrtoFirstPT(physical)

          ;Zerooutpagetables&kerneldatapage

          movr0,#0;(r0-r3)=0stostore
          movr1,#0
          movr2,#0
          movr3,#0
          movr4,r10;(r4)=firstaddresstoclear
          addr5,r10,#KDEnd-PTs;(r5)=lastaddress+1
          18stmiar4!,{r0-r3}
          stmiar4!,{r0-r3}
          cmpr4,r5
          blo%B18

          ;readthearchitectureinformation
          blGetCpuId
          movr5,r0LSR#16;r5>>=16
          andr5,r5,#0x0000000f;r5&=0x0000000f==architectureid

          ;Setup2ndlevelpagetabletomapthehighmemoryareawhichcontainsthe
          ;firstlevelpagetable,2ndlevelpagetables,kerneldatapage,etc.
          ;(r5)=architectureid

          addr4,r10,#HighPT-PTs;(r4)=ptrtohighpagetable

          cmpr5,#ARMv6;v6orlater?
          ;ARMV6_MMU
          orrger0,r10,#PTL2_KRW+PTL2_SMALL_PAGE+ARMV6_MMU_PTL2_SMALL_XN
          ;(r0)=PTEfor4K,kr/wu-/-page,uncachedunbuffered,nonexecutable
          ;PREARMV6_MMU
          orrltr0,r10,#PTL2_KRW+(PTL2_KRW<<2)+(PTL2_KRW<<4)+(PTL2_KRW<<6)
          ;NeedtoreplicateAPbitsintoall4fields
          orrltr0,r0,#PTL2_SMALL_PAGE+PREARMV6_MMU_PTL2_SMALL_XN
          ;(r0)=PTEfor4K,kr/wu-/-page,uncachedunbuffered,nonexecutable
          strr0,[r4,#0xD0*4];storetheentryinto4slotstomap16Kofprimarypagetable
          addr0,r0,#0x1000;steponthephysicaladdress
          strr0,[r4,#0xD1*4]
          addr0,r0,#0x1000;steponthephysicaladdress
          strr0,[r4,#0xD2*4]
          addr0,r0,#0x1000;steponthephysicaladdress
          strr0,[r4,#0xD3*4]

          addr8,r10,#ExceptionVectors-PTs;(r8)=ptrtovectorpage
          orrr0,r8,#PTL2_SMALL_PAGE;constructthePTE(C=B=0)

          ;;Theexceptionstacksandthevectorsaremappedasasinglekr/wpage.
          ;;Anyalternativewillusemorephysicalmemory.
          ;;Multiplemappingsdontprovideanyrealprotection:ifthevectorswereinar/opage,
          ;;theycouldstillbecorruptedviathekr/wsettingrequiredforthestacks.
          cmpr5,#ARMv6;v6orlater?
          ;ARMV6_MMU
          orrger0,r0,#PTL2_KRW
          ;PREARMV6_MMU
          orrltr0,r0,#PTL2_KRW+(PTL2_KRW<<2)+(PTL2_KRW<<4)+(PTL2_KRW<<6)
          ;NeedtoreplicateAPbitsintoall4fieldsforpre-V6MMU

          strr0,[r4,#0xF0*4];storeentryforexceptionstacksandvectors
          ;other3entriesnowunused

          addr9,r10,#KPage-PTs;(r9)=ptrtokdatapage
          orrr0,r9,#PTL2_SMALL_PAGE;(r0)=PTEfor4K(C=B=0)

          ;ARMV6_MMU(conditioncodesstillset)
          orrger0,r0,#PTL2_KRW_URO;Nosubpageaccesscontrol,sowemustsetthisalltokr/w+ur/o
          ;PREARMV6_MMU
          orrltr0,r0,#(PTL2_KRW<<0)+(PTL2_KRW<<2)+(PTL2_KRW_URO<<4)
          ;(r0)=setpermskr/wkr/wkr/w+ur/or/o
          strr0,[r4,#0xFC*4];storeentryforkerneldatapage
          orrr0,r4,#PTL1_2Y_TABLE;(r0)=1stlevelPTEforhighmemorysection
          addr1,r10,#0x4000
          strr0,[r1,#-4];storePTEinlastslotof1stleveltable

          ;Fillinfirstlevelpagetableentriestocreate"staticallymapped"regions
          ;fromthecontentsoftheOEMAddressTablearray.
          ;
          ;(r5)=architectureid
          ;(r9)=ptrtoKDatapage
          ;(r10)=ptrto1stlevelpagetable
          ;(r11)=ptrtoOEMAddressTablearray

          addr10,r10,#0x2000;(r10)=ptrto1stPTEfor"unmappedspace"

          movr0,#PTL1_SECTION
          orrr0,r0,#PTL1_KRW;(r0)=PTEfor0:1MB(C=B=0,kernelr/w)
          20movr1,r11;(r1)=ptrtoOEMAddressTablearray(physical)


          25ldrr2,[r1],#4;(r2)=virtualaddresstomapBankat
          ldrr3,[r1],#4;(r3)=physicaladdresstomapfrom
          ldrr4,[r1],#4;(r4)=numMBtomap

          cmpr4,#0;Endoftable?
          beq%F29

          ldrr12,=0x1FF00000
          andr2,r2,r12;VAneeds512MB,1MBaligned.

          ldrr12,=0xFFF00000
          andr3,r3,r12;PAneeds4GB,1MBaligned.

          addr2,r10,r2,LSR#18
          addr0,r0,r3;(r0)=PTEfornextphysicalpage

          28strr0,[r2],#4
          addr0,r0,#0x00100000;(r0)=PTEfornextphysicalpage

          subr4,r4,#1;DecrementnumberofMBleft
          cmpr4,#0
          bne%B28;MapnextMB

          bicr0,r0,#0xF0000000;ClearSectionBaseAddressField
          bicr0,r0,#0x0FF00000;ClearSectionBaseAddressField
          b%B25;Getnextelement


          29
          subr10,r10,#0x2000;(r10)=restoreaddressof1stlevelpagetable

          ;Theminimalpagemappingsaresetup.InitializetheMMUandturniton.

          ;therearesomeCPUswithpipelineissuesthatrequiresidentitymappingbeforeturningonMMU.
          ;WellcreateanidentitymappingfortheaddresswelljumptowhenturningonMMUonandremove
          ;themappingafterweturnonMMUandrunningonVirtualaddress.


          ldrr12,=0xFFF00000;(r12)=maskforsectionbits
          andr1,pc,r12;physicaladdressofwhereweare
          ;NOTE:weassumethattheKernelStartfunctionneverspamacross1Mboundary.
          orrr0,r1,#PTL1_SECTION
          orrr0,r0,#PTL1_KRW;(r0)=PTEfor1Mforcurrentphysicaladdress,C=B=0,kernelr/w
          addr7,r10,r1,LSR#18;(r7)=1stlevelPTentryfortheidentitymap
          ldrr8,[r7];(r8)=savedcontentofthe1st-levelPT
          strr0,[r7];createtheidentitymap

          movr1,#1
          mtc15r1,c3;Setupaccesstodomain0andclearother
          mtc15r10,c2;setuptranslationbase(physicalof1stlevelPT)

          movr0,#0
          mcrp15,0,r0,c8,c7,0;FlushtheI&DTLBs

          mfc15r1,c1
          orrr1,r1,#0x007F;changedtoread-mod-writeforARM920Enable:MMU,Align,DCache,WriteBuffer

          cmpr5,#ARMv6;r5stillset
          ;ARMV6_MMU
          orrger1,r1,#0x3000;vectoradjust,ICache
          orrger1,r1,#1<<23;V6-formatpagetables
          orrger1,r1,#ARMV6_U_BIT;V6-setUbit,letAbitcontrolunalignmentsupport
          ;PREARMV6_MMU
          orrltr1,r1,#0x3200;vectoradjust,ICache,ROMprotection

          ldrr0,VirtualStart
          cmpr0,#0;makesurenostallon"movpc,r0"below
          mtc15r1,c1;enabletheMMU&Caches
          movpc,r0;&jumptonewvirtualaddress
          nop

          ;MMU&cachesnowenabled.
          ;
          ;(r10)=physcialaddressof1stlevelpagetable
          ;(r7)=entryin1stlevelPTforidentitymap
          ;(r8)=saved1stlevelPTsaveat(r7)
          VStartldrr2,=FirstPT;(r2)=VAof1stlevelPT
          subr7,r7,r10;(r7)=offsetinto1st-levelPT
          strr8,[r2,r7];restorethetemporaryidentitymap
          mcrp15,0,r0,c8,c7,0;FlushtheI&DTLBs

          ;
          ;setupstackforeachmodes:currentmode=supervisormode
          ;
          ldrsp,=KStack
          addr4,sp,#KData-KStack;(r4)=ptrtoKDataStruct

          ;setupABORTstack
          movr1,#ABORT_MODE:OR:0xC0
          msrcpsr_c,r1;switchtoAbortModew/IRQsdisabled
          addsp,r4,#AbortStack-KData

          ;setupIRQstack
          movr2,#IRQ_MODE:OR:0xC0
          msrcpsr_c,r2;switchtoIRQModew/IRQsdisabled
          addsp,r4,#IntStack-KData

          ;setupFIQstack
          movr3,#FIQ_MODE:OR:0xC0
          msrcpsr_c,r3;switchtoFIQModew/IRQsdisabled
          addsp,r4,#FIQStack-KData

          ;setupUNDEFstack
          movr3,#UNDEF_MODE:OR:0xC0
          msrcpsr_c,r3;switchtoUndefinedModew/IRQsdisabled
          movsp,r4;(sp_undef)=&KData

          ;switchbacktoSupervisormode
          movr0,#SVC_MODE:OR:0xC0
          msrcpsr_c,r0;switchtoSupervisorModew/IRQsdisabled
          ldrsp,=KStack

          ;continueinitializationinC
          addr0,sp,#KData-KStack;(r0)=ptrtoKDataStruct
          strr6,[r0,#pAddrMap];storeVAofOEMAddressTableinKData
          blARMInit;callCfunctiontoperformtherestofinitializations
          ;uponreturn,(r0)=entrypointofkernel.dll

          movr12,r0
          ldrr0,=KData
          movpc,r12;jumptoentryofkernel.dll

          從上面的代碼可以看出,KernelStart()通過(guò)OEMAddressTable初始化了MMU,然后通過(guò)調(diào)用函數(shù)ARMInit()獲得kernel.dll的入口點(diǎn),最后跳轉(zhuǎn)到kernel.dll的入口點(diǎn)處。

          為了找到Kernel.dll的入口點(diǎn),用IDA反匯編kernel.dll文件,可以看到,Kernel.dll的入口點(diǎn)為NKStartup。

          NKStartup()的實(shí)現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELARM mdarm.c中,代碼如下:

          Code
          //
          //NKStartup-entrypointofkernel.dll.
          //
          //NKLoadersetuponlytheminimalmappings,whichincludesARMHigharea,andthecachedstaticmappingarea,
          //with*EVERYTHINGUNCACHED*.Interruptvectorsarenotsetupeither.So,theinitsequencereqiures:
          //(1)pickupdatapassedfromnkloader
          //(2)Findentrypointofoal,exchangeglobals,findoutthecachemode.
          //(3)fillintherestofstaticmappedarea(0xa0000000-0xbfffffff),PSLfaultingaddress,interruptvectors,
          //modstacks,etc.Then,changethecachedstaticmappingareatousecache,andflushI&DTLB.
          //(4)continuenormalloadingofkernel(findKITLdll,callOEMInitDebugSerial,etc.)
          //
          voidNKStartup(structKDataStruct*pKData)
          {
          PFN_OEMInitGlobalspfnInitGlob;
          PFN_DllMainpfnKitlEntry;
          DWORDdwCpuId=GetCpuId();

          //(1)pickupargumentsfromthenkloader
          g_pKData=pKData;
          pTOC=(constROMHDR*)pKData->dwTOCAddr;
          g_pOEMAddressTable=(PADDRMAP)pKData->pAddrMap;

          /*getarchitectureidandupdatepageprotectionattributes*/
          pKData->dwArchitectureId=(dwCpuId>>16)&0xf;
          if(pKData->dwArchitectureId>=ARMArchitectureV6){
          //v6orlater
          pKData->dwProtMask=PG_V6_PROTECTION;
          pKData->dwRead=PG_V6_PROT_READ;
          pKData->dwWrite=PG_V6_PROT_WRITE;
          pKData->dwKrwUro=PG_V6_PROT_URO_KRW;
          pKData->dwKrwUno=PG_V6_PROT_UNO_KRW;

          }else{
          //pre-v6
          pKData->dwProtMask=PG_V4_PROTECTION;
          pKData->dwRead=PG_V4_PROT_READ;
          pKData->dwWrite=PG_V4_PROT_WRITE;
          pKData->dwKrwUro=PG_V4_PROT_URO_KRW;
          pKData->dwKrwUno=PG_V4_PROT_UNO_KRW;
          }

          //initializenkglobals
          FirstROM.pTOC=(ROMHDR*)pTOC;
          FirstROM.pNext=0;
          ROMChain=&FirstROM;
          KInfoTable[KINX_PTOC]=(long)pTOC;
          KInfoTable[KINX_PAGESIZE]=VM_PAGE_SIZE;

          g_ppdirNK=(PPAGEDIRECTORY)&ArmHigh->firstPT[0];
          pKData->pNk=g_pNKGlobal;

          //(2)findentryofoal
          pfnInitGlob=(PFN_OEMInitGlobals)pKData->dwOEMInitGlobalsAddr;

          //nocheckinghere,ifOALentrypointdoesntexist,wecantcontinue
          g_pOemGlobal=pfnInitGlob(g_pNKGlobal);
          g_pOemGlobal->dwMainMemoryEndAddress=pTOC->ulRAMEnd;
          pKData->pOem=g_pOemGlobal;

          //setupglobals
          pVMProc=g_pprcNK;
          pActvProc=g_pprcNK;

          g_pNKGlobal->pfnWriteDebugString=g_pOemGlobal->pfnWriteDebugString;

          //(3)setupvectors,UCmappings,modestacks,etc.
          ARMSetup();

          //
          //cacheisenabledfromhereon
          //

          //(4)commonstartupcode.

          //trytoloadKITLifexist
          if((pfnKitlEntry=(PFN_DllMain)g_pOemGlobal->pfnKITLGlobalInit)||
          (pfnKitlEntry=(PFN_DllMain)FindROMDllEntry(pTOC,KITLDLL))){
          (*pfnKitlEntry)(NULL,DLL_PROCESS_ATTACH,(DWORD)NKKernelLibIoControl);
          }

          #ifdefDEBUG
          CurMSec=dwPrevReschedTime=(DWORD)-200000;//~3minutesbeforewrap
          #endif

          OEMInitDebugSerial();

          //debugchkonlyworksafterwehavesomethingtoprintto.
          DEBUGCHK(pKData==(structKDataStruct*)PUserKData);
          DEBUGCHK(pKData==&ArmHigh->kdata);

          OEMWriteDebugString((LPWSTR)NKSignon);

          /*Copyinterlockedapicodeintothekpage*/
          DEBUGCHK(sizeof(structKDataStruct)<=FIRST_INTERLOCK);
          DEBUGCHK((InterlockedEnd-InterlockedAPIs)+FIRST_INTERLOCK<=0x400);
          memcpy((char*)g_pKData+FIRST_INTERLOCK,InterlockedAPIs,InterlockedEnd-InterlockedAPIs);

          /*setupprocessorversioninformation*/
          CEProcessorType=(dwCpuId>>4)&0xFFF;
          CEProcessorLevel=4;
          CEProcessorRevision=(WORD)dwCpuId&0x0f;
          CEInstructionSet=PROCESSOR_ARM_V4I_INSTRUCTION;

          RETAILMSG(1,(L"ProcessorType=%4.4xRevision=%drn",CEProcessorType,CEProcessorRevision));
          RETAILMSG(1,(L"OEMAddressTable=%8.8lxrn",g_pOEMAddressTable));

          OEMInit();//initializefirmware

          //flushI&DTLB
          OEMCacheRangeFlush(NULL,0,CACHE_SYNC_FLUSH_TLB);

          KernelFindMemory();

          DEBUGMSG(1,(TEXT("NKStartupdone,startingupkernel.rn")));

          KernelStart();

          //neverreturned
          DEBUGCHK(0);
          }

          NKStartup()的代碼就不多解釋了,注釋已經(jīng)很詳細(xì)。該函數(shù)的最后又調(diào)用了KernelStart ()函數(shù)。注意這里的KernelStart()跟上面曾提到的KernelStart()是不一樣的。這里KernelStart()的實(shí)現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELARMarmtrap.s中,代碼和反匯編的對(duì)比如下圖所示。
          可以看到,這里調(diào)用了KernelInit()和FirstSchedule()這兩個(gè)函數(shù)。先說(shuō)FirstSchedule(),它開(kāi)始了WinCE6.0的第一個(gè)調(diào)度。它的實(shí)現(xiàn)跟KernelStart()在同一文件中,而實(shí)現(xiàn)代碼跟WinCE5.0中完全一樣。接下來(lái),我們繼續(xù)跟蹤KernelInit()函數(shù),其實(shí)現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELnkinit.c中,代碼如下:

          Code
          //------------------------------------------------------------------------------
          //KernelInit-Kernelinitializationbeforeschedulingthe1stthread
          //------------------------------------------------------------------------------

          voidKernelInit(void)
          {
          #ifdefDEBUG
          g_pNKGlobal->pfnWriteDebugString(TEXT("WindowsCEKernelInitrn"));
          #endif
          APICallInit();//setupAPIset
          HeapInit();//setupkernelheap
          InitMemoryPool();//setupphysicalmemory
          PROCInit();//initializeprocess
          VMInit(g_pprcNK);//setupVMforkernel
          THRDInit();//initializethreads
          MapfileInit();

          #ifdefDEBUG
          g_pNKGlobal->pfnWriteDebugString(TEXT("Schedulingthefirstthread.rn"));
          #endif
          }

          這段代碼跟WinCE5.0中的結(jié)構(gòu)基本一致,但實(shí)際上有很大的不同。跟WinCE6.0啟動(dòng)最緊密的函數(shù)是THRDInit (),這之前都是做相應(yīng)的初始化。THRDInit ()的實(shí)現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELthread.c中,代碼如下:

          Code
          //------------------------------------------------------------------------------
          //THRDInit-initializethreadhandling(calledatsystemstartup)
          //------------------------------------------------------------------------------
          voidTHRDInit(void)
          {
          LPBYTEpStack;

          DEBUGLOG(1,g_pprcNK);

          //dontallowthreadcreateonememorydropbelow1%available
          if(g_cMinPageThrdCreateg_cMinPageThrdCreate=PageFreeCount/100;
          }

          //mapW32threadpriorityifOEMchooseto
          if(g_pOemGlobal->pfnMapW32Priority){
          BYTEprioMap[MAX_WIN32_PRIORITY_LEVELS];
          inti;
          memcpy(prioMap,W32PrioMap,sizeof(prioMap));
          g_pOemGlobal->pfnMapW32Priority(MAX_WIN32_PRIORITY_LEVELS,prioMap);
          //validatethethepriorityismono-increase
          for(i=0;iif(prioMap[i]>=prioMap[i+1])
          break;
          }

          DEBUGMSG((MAX_WIN32_PRIORITY_LEVELS-1)!=i,(L"ProcInit:InvalidprioritymapprovidedbyOEM,Ignored!rn"));
          if((MAX_WIN32_PRIORITY_LEVELS-1)==i){
          memcpy(W32PrioMap,prioMap,sizeof(prioMap));
          }
          }

          //allocatememoryforthe1stthread
          pCurThread=AllocMem(HEAP_THREAD);
          DEBUGCHK(pCurThread);

          dwCurThId=(DWORD)HNDLCreateHandle(&cinfThread,pCurThread,g_pprcNK)&~1;
          DEBUGCHK(dwCurThId);

          InitThreadStruct(pCurThread,(HANDLE)dwCurThId,g_pprcNK,THREAD_RT_PRIORITY_ABOVE_NORMAL);

          if(g_pOemGlobal->cbCoProcRegSize){

          DEBUGCHK(g_pOemGlobal->pfnInitCoProcRegs);
          DEBUGCHK(g_pOemGlobal->pfnSaveCoProcRegs);
          DEBUGCHK(g_pOemGlobal->pfnRestoreCoProcRegs);

          //checkthedebugregisterrelatedvalues.
          if(g_pOemGlobal->cbCoProcRegSize>MAX_COPROCREGSIZE){
          g_pOemGlobal->cbCoProcRegSize=g_pOemGlobal->fSaveCoProcReg=0;
          }else{
          PNAMEpTmp=AllocName(g_pOemGlobal->cbCoProcRegSize);
          DEBUGCHK(pTmp);
          g_dwCoProcPool=pTmp->wPool;
          FreeName(pTmp);
          }
          }else{
          g_pOemGlobal->fSaveCoProcReg=FALSE;
          }
          DEBUGMSG(ZONE_SCHEDULE,(TEXT("cbCoProcRegSize=%drn"),g_pOemGlobal->cbCoProcRegSize));

          AddToDListHead(&g_pprcNK->thrdList,&pCurThread->thLink);
          g_pprcNK->wThrdCnt++;


          #ifdefSHx
          SetCPUGlobals();
          OEMCacheRangeFlush(0,0,CACHE_SYNC_ALL);
          #endif


          if(!OpenExecutable(NULL,TEXT("NK.EXE"),&g_pprcNK->oe,TOKEN_SYSTEM,NULL,0)){
          LoadE32(&g_pprcNK->oe,&g_pprcNK->e32,0,0,0);
          g_pprcNK->BasePtr=(LPVOID)g_pprcNK->e32.e32_vbase;
          UpdateKmodVSize(&g_pprcNK->oe,&g_pprcNK->e32);
          }

          //create/setupstack
          pStack=VMCreateStack(g_pprcNK,KRN_STACK_SIZE);
          pCurThread->dwOrigBase=(DWORD)pStack;
          pCurThread->dwOrigStkSize=KRN_STACK_SIZE;
          pCurThread->tlsSecure=pCurThread->tlsNonSecure=pCurThread->tlsPtr=TLSPTR(pStack,KRN_STACK_SIZE);
          pCurThread->hTok=TOKEN_SYSTEM;

          //Saveoffthethreadsprogramcounterforgettingitsnamelater.
          pCurThread->dwStartAddr=(DWORD)SystemStartupFunc;

          MDSetupThread(pCurThread,(LPVOID)SystemStartupFunc,0,TH_KMODE,0);

          CELOG_ThreadCreate(pCurThread,g_pprcNK,NULL);

          MakeRun(pCurThread);
          DEBUGMSG(ZONE_SCHEDULE,(TEXT("Scheduler:Createdmasterthread%8.8lxrn"),pCurThread));

          }

          可以看到,這里開(kāi)始了一個(gè)線程,線程處理函數(shù)為SystemStartupFunc(),其實(shí)現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELschedule.c,實(shí)現(xiàn)代碼如下:

          Code
          //------------------------------------------------------------------------------
          void
          SystemStartupFunc(
          ulongparam
          )
          {
          HANDLEhTh;

          //recordPendEventaddressforSetInterruptEvent
          KInfoTable[KINX_PENDEVENTS]=(DWORD)&PendEvents1;

          KernelInit2();

          //adjustalarmresolutionifititsnotinbound
          if(g_pOemGlobal->dwAlarmResolutiong_pOemGlobal->dwAlarmResolution=MIN_NKALARMRESOLUTION_MSEC;
          elseif(g_pOemGlobal->dwAlarmResolution>MAX_NKALARMRESOLUTION_MSEC)
          g_pOemGlobal->dwAlarmResolution=MAX_NKALARMRESOLUTION_MSEC;

          VERIFY(LoaderInit());

          //initializethecompiler/GScookie-thismusthappenbeforeotherthreads
          //startrunning
          __security_init_cookie();

          PagePoolInit();

          //Thiscanonlybedoneaftertheloaderinitialization
          LoggerInit();//InitializationforCeLog,profiler,code-coverage,etc.
          SysDebugInit();//initializeSystemDebugger(HWDebugstub,Kerneldumpcapture,SWKernelDebugstub)

          //dothisnow,sothatwecontinuerunningafterwevecreatedthenewthread
          #ifdefSTART_KERNEL_MONITOR_THREAD
          hTh=CreateKernelThread(Monitor1,0,THREAD_RT_PRIORITY_ABOVE_NORMAL,0);
          HNDLCloseHandle(g_pprcNK,hTh);
          #endif

          pCleanupThread=pCurThread;
          hAlarmThreadWakeup=NKCreateEvent(0,0,0,0);
          DEBUGCHK(hAlarmThreadWakeup);
          InitializeCriticalSection(&rtccs);
          IntrEvents[SYSINTR_RTC_ALARM-SYSINTR_DEVICES]=LockIntrEvt(hAlarmThreadWakeup);
          DEBUGCHK(IntrEvents[SYSINTR_RTC_ALARM-SYSINTR_DEVICES]->phdIntr);

          //GivetheOEMafinalchancetodoamorefull-featuredinitbeforeany
          //appsarestarted
          KernelIoctl(IOCTL_HAL_POSTINIT,NULL,0,NULL,0,NULL);

          InitMsgQueue();
          InitWatchDog();

          //createthepowerhandlereventandguardthread
          hEvtPwrHndlr=NKCreateEvent(NULL,FALSE,FALSE,NULL);
          DEBUGCHK(hEvtPwrHndlr);
          hTh=CreateKernelThread(PowerHandlerGuardThrd,NULL,THREAD_PWR_GUARD_PRIORITY,0);
          HNDLCloseHandle(g_pprcNK,hTh);

          //dirtypageevent,initiallyset
          hEvtDirtyPage=NKCreateEvent(NULL,FALSE,TRUE,NULL);
          DEBUGCHK(hEvtDirtyPage);

          //wedontwanttowasteathreadhere(createaseparateforcleaningdirtypages).
          //Instead,RunAppsthreadwillbecome"CleanDirtyPage"threadoncefilesysstarted
          hTh=CreateKernelThread(RunApps,0,THREAD_RT_PRIORITY_NORMAL,0);
          HNDLCloseHandle(g_pprcNK,hTh);

          #defineONE_DAY86400000

          while(1){
          KCall((PKFN)SetThreadBasePrio,pCurThread,dwNKAlarmThrdPrio);
          NKWaitForSingleObject(hAlarmThreadWakeup,ONE_DAY);
          NKRefreshKernelAlarm();
          PageOutIfNeeded();
          }
          }

          這里創(chuàng)建了一個(gè)內(nèi)核線程,處理函數(shù)為RunApps,繼續(xù)跟蹤RunApps,其實(shí)現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELkmisc.c中,代碼如下:

          Code
          DWORDWINAPI
          RunApps(
          LPVOIDparam
          )
          {
          HMODULEhFilesys;
          DEBUGMSG(ZONE_ENTRY,(L"RunAppsstartedrn"));

          CELOG_LaunchingFilesys();

          hFilesys=(HMODULE)NKLoadLibraryEx(L"filesys.dll",MAKELONG(LOAD_LIBRARY_IN_KERNEL,LLIB_NO_PAGING),NULL);

          if(hFilesys){
          FARPROCpfnMain=GetProcAddressA(hFilesys,(LPCSTR)2);//WinMainoffilesys
          HANDLEhFSReady,hTh;

          DEBUGCHK(pfnMain);

          hFSReady=NKCreateEvent(NULL,TRUE,FALSE,TEXT("SYSTEM/FSReady"));
          hTh=CreateKernelThread((LPTHREAD_START_ROUTINE)pfnMain,hFilesys,THREAD_RT_PRIORITY_NORMAL,0);

          DEBUGCHK(hTh&&hFSReady);
          HNDLCloseHandle(g_pprcNK,hTh);

          //IfpSignalStartedisNULL,wedonthavefilesys(tinykern).Dontbotherwaitingforit.
          if(pSignalStarted){
          NKWaitForSingleObject(hFSReady,INFINITE);

          DEBUGCHK(SystemAPISets[SH_FILESYS_APIS]);

          //InitializeMUI-Resourceloader(requiresregistry)
          InitMUILanguages();

          //Readsystemsettingsfromregistry
          InitSystemSettings();

          //signalfilesysthatweredone
          (*pSignalStarted)(0);
          }
          HNDLCloseHandle(g_pprcNK,hFSReady);

          }else{
          RETAILMSG(1,(L"Filesysdoesntexist,noappstartedrn"));
          }

          //insteadofexiting,weremakethisthreadcleaningdirtypagesinthebackground.
          CleanPagesInTheBackground();

          //shouldveneverreturned
          DEBUGCHK(0);
          NKExitThread(0);

          return0;
          }
          終于啟動(dòng)filesys.dll了。這個(gè)過(guò)程簡(jiǎn)單說(shuō)明一下,啟動(dòng)filesys.dll后等待其執(zhí)行的情況,在完成了文件系統(tǒng)的相應(yīng)的初始化之后,這里繼續(xù)初始化MUI和系統(tǒng)設(shè)置,完成后再通知filesys這邊的工作已經(jīng)完成,filesys繼續(xù)啟動(dòng)。這一部分的具體內(nèi)容請(qǐng)參考MSDN,F(xiàn)ile System Boot Process:http://msdn.microsoft.com/en-us/library/aa912276.aspx。總之,filesys會(huì)完成WinCE的最后啟動(dòng)過(guò)程,包括gwes.dll和explorer.exe等。至此,WinCE6.0啟動(dòng)完成,如果有LCD且驅(qū)動(dòng)能正常工作,現(xiàn)在就應(yīng)該能看見(jiàn)可愛(ài)的WinCE6.0的界面了。

          呵,沒(méi)想到WinCE6.0的啟動(dòng)過(guò)程竟然這么繁長(zhǎng)。不過(guò),弄清楚這個(gè)啟動(dòng)流程對(duì)于移植BSP相當(dāng)有好處??偨Y(jié)一下整個(gè)過(guò)程,如下圖所示。


          本文通過(guò)跟蹤代碼的方式,介紹了WinCE6.0的啟動(dòng)流程。流于表面了一點(diǎn),很多細(xì)節(jié)應(yīng)該進(jìn)一步研究,以后再慢慢看吧。文中有不確切的地方,也請(qǐng)您不吝賜教.



          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();